﻿#include "qcpumonitor.h"


QCpuMonitor::QCpuMonitor() {
#ifdef Q_OS_WIN
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    m_processorCount = sysInfo.dwNumberOfProcessors;

    // 初始化首次采样
    FILETIME idle, kernel, user;
    GetSystemTimes(&idle, &kernel, &user);

    m_winData.lastIdleTime.LowPart = idle.dwLowDateTime;
    m_winData.lastIdleTime.HighPart = idle.dwHighDateTime;
    m_winData.lastKernelTime.LowPart = kernel.dwLowDateTime;
    m_winData.lastKernelTime.HighPart = kernel.dwHighDateTime;
    m_winData.lastUserTime.LowPart = user.dwLowDateTime;
    m_winData.lastUserTime.HighPart = user.dwHighDateTime;
    m_winData.initialized = true;
#else
    QFile file("/proc/cpuinfo");
    if (!file.open(QIODevice::ReadOnly)){
        QTextStream in(&file);
        QString line;
        int processorCount = 0;

        while (!in.atEnd()) {
            line = in.readLine();
            if (line.startsWith("processor")) {
                processorCount++;
            }
        }
        file.close();
        m_processorCount = processorCount > 0 ? processorCount : 1;
    }
#endif
}

QCpuMonitor::~QCpuMonitor()
{

}

double QCpuMonitor::systemUsage() {
#ifdef Q_OS_WIN
    FILETIME idleTime, kernelTime, userTime;
    if (!GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
        return -1.0;
    }

    // 转换时间格式（100纳秒单位）
    auto toUInt64 = [](FILETIME& ft) {
        return (ULARGE_INTEGER{ft.dwLowDateTime, ft.dwHighDateTime}).QuadPart;
    };

    // 当前值采集
    const quint64 currentIdle = toUInt64(idleTime);
    const quint64 currentKernel = toUInt64(kernelTime);
    const quint64 currentUser = toUInt64(userTime);

    // 首次采样处理
    static quint64 lastIdle = currentIdle;
    static quint64 lastTotal = currentKernel + currentUser;
    if (lastTotal == 0) { // 首次调用初始化
        lastIdle = currentIdle;
        lastTotal = currentKernel + currentUser;
        return 0.0;
    }

    // 计算差值（需考虑时间单位）
    const quint64 idleDiff = currentIdle - lastIdle;
    const quint64 totalDiff = (currentKernel + currentUser) - lastTotal;

    // 更新基准值
    lastIdle = currentIdle;
    lastTotal = currentKernel + currentUser;

    // 异常处理（关键修复点）
    if (totalDiff == 0 || idleDiff > totalDiff) {
        return 0.0; // 此情况应极少发生
    }

    // 最终计算
    return (1.0 - (double)idleDiff / totalDiff) * 100 ;
#else
    QFile file("/proc/stat");
    if (!file.open(QIODevice::ReadOnly)) {
        return -1.0;
    }

    QTextStream in(&file);
    QString line = in.readLine();
    QStringList list = line.split(' ', Qt::SkipEmptyParts);

    if (list.size() < 5) return -1.0;

    const quint64 user = list[1].toULongLong();
    const quint64 nice = list[2].toULongLong();
    const quint64 system = list[3].toULongLong();
    const quint64 idle = list[4].toULongLong();

    const quint64 total = user + nice + system + idle;

    if (!m_linuxData.initialized) {
        m_linuxData.lastTotal = total;
        m_linuxData.lastIdle = idle;
        m_linuxData.initialized = true;
        return 0.0;
    }

    const quint64 totalDiff = total - m_linuxData.lastTotal;
    const quint64 idleDiff = idle - m_linuxData.lastIdle;

    m_linuxData.lastTotal = total;
    m_linuxData.lastIdle = idle;

    return totalDiff > 0 ? (totalDiff - idleDiff) * 100.0 / totalDiff : 0.0;
#endif
}

double QCpuMonitor::processUsage(qint64 pid) {
#ifdef Q_OS_WIN
    if (pid == 0) pid = GetCurrentProcessId();

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    if (!hProcess) return -1.0;

    FILETIME createTime, exitTime, kernelTime, userTime;
    if (!GetProcessTimes(hProcess, &createTime, &exitTime, &kernelTime, &userTime)) {
        CloseHandle(hProcess);
        return -1.0;
    }

    ULARGE_INTEGER kernel = { {kernelTime.dwLowDateTime, kernelTime.dwHighDateTime} };
    ULARGE_INTEGER user = { {userTime.dwLowDateTime, userTime.dwHighDateTime} };

    static quint64 lastTotal = 0;
    static quint64 lastTick = GetTickCount64();

    const quint64 currentTotal = kernel.QuadPart + user.QuadPart;
    const quint64 currentTick = GetTickCount64();

    double usage = 0.0;
    if (lastTotal != 0 && (currentTick - lastTick) > 0) {
        const quint64 cpuDiff = currentTotal - lastTotal;
        const quint64 timeDiff = currentTick - lastTick;
        usage = (cpuDiff * 100.0) / (timeDiff * 10000);
    }

    lastTotal = currentTotal;
    lastTick = currentTick;
    CloseHandle(hProcess);
    return qBound(0.0, usage, 100.0);
#else
    if (pid == 0) pid = getpid();

    QString path = QString("/proc/%1/stat").arg(pid);
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly)) return -1.0;

    QTextStream in(&file);
    QStringList list = in.readLine().split(' ', Qt::SkipEmptyParts);
    if (list.size() < 22) return -1.0;

    quint64 utime = list[13].toULongLong();
    quint64 stime = list[14].toULongLong();
    quint64 totalTime = utime + stime;

    static quint64 lastTotal = 0;
    static quint64 lastTime = QDateTime::currentMSecsSinceEpoch();

    quint64 currentTime = QDateTime::currentMSecsSinceEpoch();
    quint64 timeDiff = currentTime - lastTime;

    double usage = 0.0;
    if (lastTotal != 0 && timeDiff > 0) {
        quint64 cpuDiff = totalTime - lastTotal;
        usage = (cpuDiff * 100.0) / (timeDiff * sysconf(_SC_CLK_TCK));
        usage /= m_processorCount;
    }

    lastTotal = totalTime;
    lastTime = currentTime;
    return qBound(0.0, usage, 100.0);
#endif
}
